/**
 * Mixing glue with lint is probably something you never want to do in real
 * life, but in this project it helps the linter do its job. And sometimes the
 * test suite too.
 *
 * This script creates `index.ts` files in each package directory that simply
 * re-export the exports of the real main file. This is necessary for when all
 * the packages are run under a common context (instead of each individually).
 * This is because the symlinks yarn makes for each package are descendants of
 * the context node is running in and therefore aren't treated as modules, only
 * as directories. Therefore package.json isn't considered and we need an index
 * file (like index.ts) to redirect to the right file.
 */

import { promises as fs } from 'node:fs';
import path from 'node:path';

import { getPackageInfo } from './utils';

// NOTE: this interface only defines the fields in the package.json that are
// used in this script
interface PartialPackageManifest {
  main?: string;
}

/**
 * A heuristic to convert the `main` value from the package.json from its output
 * location to the source location (e.g. dist/ to src/ & .js to .ts).
 */
function convertMainToSrc(main: string): string {
  return main.replace(/^dist\//, 'src/').replace(/\.js$/, '.ts');
}

(async () => {
  const baseTypedocJson = path.resolve(__dirname, '../typedoc.base.json');
  const pkgs = await getPackageInfo();

  // Run each package in parallel
  await Promise.all(
    pkgs.map(async (pkg) => {
      // Extract the `main` field from the package.json
      const { main } = pkg.manifest as PartialPackageManifest;

      // Skip packages that have no main (e.g. the cli as of writing)
      if (main === undefined) {
        return;
      }

      // Read the main file
      const srcMain = convertMainToSrc(main);
      const srcMainFull = path.resolve(pkg.path, srcMain);
      const srcMainContents = await fs.readFile(srcMainFull, {
        encoding: 'utf8',
      });

      // Detect if the package has a default export
      const hasDefault = /export\s+default/i.test(srcMainContents);

      // Write the facade entry-point file
      const importTarget = './' + srcMain.replace(/\.ts$/, '');
      const facadeFilePath = path.resolve(pkg.path, 'index.ts');
      const typedocJsonPath = path.resolve(pkg.path, 'typedoc.json');
      await fs.writeFile(
        typedocJsonPath,
        JSON.stringify(
          {
            $schema: 'https://typedoc.org/schema.json',
            extends: [baseTypedocJson],
            entryPoints: [srcMain],
          },
          null,
          2,
        ),
      );
      let facadeFileContents =
        '// ⚠️ AUTOGENERATED ⚠️ AUTOGENERATED ⚠️ AUTOGENERATED ⚠️\n' +
        '// This file was automatically generated by `tools/gen-ts-glue.ts`. Do not modify directly if you want to keep your changes.\n' +
        `export * from "${importTarget}";\n`;
      if (hasDefault) {
        facadeFileContents +=
          `import defaultExport from "${importTarget}";\n` +
          `export default defaultExport;\n`;
      }
      await fs.writeFile(facadeFilePath, facadeFileContents);
    }),
  );
})().catch(console.error);
